﻿#if _MSC_VER >= 1600    // VC2010
#pragma execution_character_set("utf-8")
#endif
#include <QtGui>
#include <QSettings>
#include "FileLink.h"
#define _WIN32_WINNT  0x0600
#include <windows.h>
#include <QSysInfo>

extern QDir	g_projectDir;

CFileLink::CFileLink(QWidget *parent, Qt::WindowFlags flags)
	: QMainWindow(parent, flags)
{
	setupUi(this);

	// Demonstrating look and feel features
	treeViewSrc->setAnimated(false);
	treeViewSrc->setIndentation(20);
	treeViewSrc->setSortingEnabled(true);

	treeViewDst->setAnimated(false);
	treeViewDst->setIndentation(20);
	treeViewDst->setSortingEnabled(true);

	QSettings settings("CFileLink", "FileLink");
	restoreGeometry(settings.value("geometry").toByteArray());
	restoreState(settings.value("windowState").toByteArray());
	treeViewSrc->header()->restoreState(settings.value("treeViewSrc").toByteArray());
	treeViewDst->header()->restoreState(settings.value("treeViewDst").toByteArray());
	splitter->restoreState(settings.value("splitter").toByteArray());

	cboFilter->addItem("*.*");
	cboFilter->addItem("* *.h *.cpp *.ui *.rc *.qrc *.vcproj *.pri *.pro *.xml *.png *.jpg *.bmp *.gif *.ico ");
	cboFilter->setCurrentIndex(0);

	for(int i=0;  i<10; i++)
	{
		QString strPath = settings.value(QString("srcFolder%1").arg(i)).toString();
		if(!strPath.isEmpty())
			cboFolderSrc->addItem(strPath);
	}
	QString strPathSrc = settings.value(QString("srcFolder")).toString();
	int idx = cboFolderSrc->findText(strPathSrc);
	cboFolderSrc->setCurrentIndex(idx);

	for(int i=0;  i<10; i++)
	{
		QString strPath = settings.value(QString("dstFolder%1").arg(i)).toString();
		if(!strPath.isEmpty())
			cboFolderDst->addItem(strPath);
	}
	QString strPathDst = settings.value(QString("dstFolder")).toString();
	idx = cboFolderDst->findText(strPathDst);
	cboFolderDst->setCurrentIndex(idx);

	QItemSelectionModel *selModelSrc = treeViewSrc->selectionModel();
	if(selModelSrc)
		connect(selModelSrc,SIGNAL(currentRowChanged (const QModelIndex&, const QModelIndex&)),this,SLOT(slot_srcSelChange(const QModelIndex&, const QModelIndex&))); 

	QItemSelectionModel *selModelDst = treeViewDst->selectionModel();
	if(selModelDst)
		connect(selModelDst,SIGNAL(currentRowChanged (const QModelIndex&, const QModelIndex&)),this,SLOT(slot_dstSelChange(const QModelIndex&, const QModelIndex&))); 

	QSysInfo::WinVersion winv = QSysInfo::windowsVersion();
	if(winv == QSysInfo::WV_2003 || winv == QSysInfo::WV_XP)
		m_bIsXP = true;
	else
		m_bIsXP = false;

	connect(cboFilter,SIGNAL(editTextChanged (const QString &)),this,SLOT(slot_cboFilter_editTextChanged(const QString &))); 
}

CFileLink::~CFileLink()
{
	QSettings settings("CFileLink", "FileLink");
	settings.setValue("geometry", saveGeometry());
	settings.setValue("windowState", saveState());
	settings.setValue("treeViewSrc",treeViewSrc->header()->saveState());
	settings.setValue("treeViewDst",treeViewDst->header()->saveState());
	settings.setValue("splitter",splitter->saveState());
	settings.setValue("srcFolder",cboFolderSrc->currentText());
	settings.setValue("dstFolder",cboFolderDst->currentText());
}

void CFileLink::on_btnFolderOpenSrc_clicked()
{
	QString strDirDefalut = g_projectDir.absolutePath();

	QString strDir = QFileDialog::getExistingDirectory(this, tr("打开目录"),
		strDirDefalut,
		QFileDialog::ShowDirsOnly| QFileDialog::DontResolveSymlinks);

	if(strDir.isEmpty())
		return;

	int idx = cboFolderSrc->findText(strDir);
	if(idx==-1)
	{
		cboFolderSrc->addItem(strDir);
		idx = cboFolderSrc->findText(strDir);
	}

	if(idx>=0)
		cboFolderSrc->setCurrentIndex(idx);
}

void CFileLink::on_btnFolderOpenDst_clicked()
{
	QString strDirDefalut = g_projectDir.absolutePath();

	QString strDir = QFileDialog::getExistingDirectory(this, tr("打开目录"),
		strDirDefalut,
		QFileDialog::ShowDirsOnly| QFileDialog::DontResolveSymlinks);

	if(strDir.isEmpty())
		return;

	int idx = cboFolderDst->findText(strDir);
	if(idx>0)
	{
		cboFolderDst->removeItem(idx);
		cboFolderDst->insertItem(0,strDir);
		cboFolderDst->setCurrentIndex(0);
	}
	else if(idx==-1)
	{
		cboFolderDst->insertItem(0,strDir);
		cboFolderDst->setCurrentIndex(0);
	}

}

void CFileLink::on_cboFolderSrc_currentIndexChanged(QString strFolder)
{
	if(!OpenFolder(cboFolderSrc,strFolder))
		return;

	QSettings settings("CFileLink", "FileLink");
	for(int i=0; i<cboFolderSrc->count() && i<10;i++)
	{
		settings.setValue(QString("srcFolder%1").arg(i), cboFolderSrc->itemText(i));
	}
}

void CFileLink::on_cboFolderDst_currentIndexChanged(QString strFolder)
{
	if(!OpenFolder(cboFolderDst,strFolder))
		return;
	QSettings settings("CFileLink", "FileLink");
	for(int i=0; i<cboFolderDst->count() && i<10;i++)
	{
		settings.setValue(QString("dstFolder%1").arg(i), cboFolderDst->itemText(i));
	}
}

bool CFileLink::OpenFolder(QComboBox *cboFolder,const QString &strFolder)
{
	if(strFolder.isEmpty())
		return false;
	QDir dir(strFolder);
	if(!dir.exists())
		return false;
	QTreeView *treeView = treeViewSrc;
	CDirModel *dirModel = &m_dirModelSrc;
	if(cboFolder==cboFolderDst)
	{
		treeView = treeViewDst;
		dirModel = &m_dirModelDst;
	}

	if(treeView->model()==NULL)
	{
// 		dirModel->setReadOnly(false);            //设置可以修改
		dirModel->setRootPath(strFolder);
		treeView->setModel(dirModel);
		dirModel->setNameFilterDisables(false);
		QStringList filters = cboFilter->currentText().split(" ",QString::SkipEmptyParts);
		dirModel->setNameFilters(filters);
	}
	treeView->setRootIndex(dirModel->index(strFolder));
// 	dirModel->setRootPath(strFolder);
//  	QModelIndex rootIndex = dirModel->index(strFolder);
// 	if(rootIndex.isValid())
// 		treeView->setRootIndex(rootIndex);
	return true;
}

void CFileLink::slot_srcSelChange ( const QModelIndex & current, const QModelIndex & previous )
{
	if(!current.isValid())
		return;
	QFileInfo fiSrc = m_dirModelSrc.fileInfo(current);
	if(!fiSrc.exists())
		return;
	QString strFolderSrc = cboFolderSrc->currentText();strFolderSrc.replace("\\","/");
	QString strFolderDst = cboFolderDst->currentText();strFolderDst.replace("\\","/");
	QString strDstFile = fiSrc.filePath();
	strDstFile.replace(strFolderSrc,strFolderDst);
	QModelIndex idx = m_dirModelDst.index(strDstFile);
	if(!idx.isValid())
		return;

	QItemSelectionModel *selModel = treeViewDst->selectionModel();
	if(selModel==NULL)
		return;
	selModel->blockSignals(true);
	selModel->clearSelection();
	selModel->select(idx,QItemSelectionModel::SelectCurrent|QItemSelectionModel::Rows);
	selModel->blockSignals(false);
	treeViewDst->scrollTo(idx);
}

void CFileLink::slot_dstSelChange ( const QModelIndex & current, const QModelIndex & previous )
{
	if(!current.isValid())
		return;
	QFileInfo fiDst = m_dirModelDst.fileInfo(current);
	if(!fiDst.exists())
		return;
	QString strFolderSrc = cboFolderSrc->currentText();strFolderSrc.replace("\\","/");
	QString strFolderDst = cboFolderDst->currentText();strFolderDst.replace("\\","/");
	QString strSrcFile = fiDst.filePath();
	strSrcFile.replace(strFolderDst,strFolderSrc);
	QModelIndex idx = m_dirModelSrc.index(strSrcFile);
	if(!idx.isValid())
		return;

	QItemSelectionModel *selModel = treeViewSrc->selectionModel();
	if(selModel==NULL)
		return;
	selModel->blockSignals(true);
	selModel->clearSelection();
	selModel->select(idx,QItemSelectionModel::SelectCurrent|QItemSelectionModel::Rows);
	selModel->blockSignals(false);
	treeViewSrc->scrollTo(idx);
}

bool CFileLink::copyDirectoryFiles(const QString &fromDir, const QString &toDir, bool coverFileIfExist)
{
	QDir sourceDir(fromDir);
	QDir targetDir(toDir);
	if(!targetDir.exists()){    /**< 如果目标目录不存在，则进行创建 */
		if(!targetDir.mkpath(toDir))
			return false;
	}

	QFileInfoList fileInfoList = sourceDir.entryInfoList();
	foreach(QFileInfo fileInfo, fileInfoList){
		if(fileInfo.fileName() == "." || fileInfo.fileName() == "..")
			continue;

		if(fileInfo.isDir()){    /**< 当为目录时，递归的进行copy */
			if(!copyDirectoryFiles(fileInfo.filePath(),
				targetDir.filePath(fileInfo.fileName()),
				coverFileIfExist))
				return false;
		}
		else{            /**< 当允许覆盖操作时，将旧文件进行删除操作 */
			if(coverFileIfExist && targetDir.exists(fileInfo.fileName())){
				targetDir.remove(fileInfo.fileName());
			}

			/// 进行文件copy
			if(!QFile::copy(fileInfo.filePath(),
				targetDir.filePath(fileInfo.fileName()))){
					return false;
			}
		}
	}
	return true;
}
void CFileLink::on_btnCopy_clicked()
{
	QItemSelectionModel *selModel = treeViewSrc->selectionModel();
	if(selModel==NULL)
		return;
	QString strFolderSrc = cboFolderSrc->currentText();strFolderSrc.replace("\\","/");
	QString strFolderDst = cboFolderDst->currentText();strFolderDst.replace("\\","/");

	QApplication::setOverrideCursor(Qt::WaitCursor);
	QModelIndexList modelList = selModel->selectedRows();
	for(int i=0; i<modelList.size(); i++)
	{
		QFileInfo fiSrc = m_dirModelSrc.fileInfo(modelList[i]);
		if(fiSrc.isDir())
		{
			QString strPathSrc = fiSrc.filePath();
			QString strPathDst = strPathSrc;
			strPathDst.replace(strFolderSrc,strFolderDst);
			copyDirectoryFiles(strPathSrc,strPathDst,true);

// 			QModelIndex idx = m_dirModelDst.index(strPathDst);
// 			if(idx.isValid())	
// 			{	// 目录已经存在
// 				continue;
// 			}
// 			else
// 			{ // 不存在则新建目录
// 				QDir dirNew(strPathDst);
// 				bool bOK = dirNew.mkpath(strPathDst.replace("/","\\"));
// 			}

		}
		else if(fiSrc.isFile())
		{
			QString strPathSrc = fiSrc.filePath();
			QString strPathDst = strPathSrc;
			strPathDst.replace(strFolderSrc,strFolderDst);
			QModelIndex idx = m_dirModelDst.index(strPathDst);
			if(idx.isValid())	
			{	// 文件已经存在
				continue;
			}
			else
			{
				QDir dirParent(fiSrc.path());
				QString strParentPath = dirParent.path();
				strParentPath.replace(strFolderSrc,strFolderDst);
				dirParent.setPath(strParentPath);
				bool bExist = dirParent.exists();
				if(!bExist)
					bExist = dirParent.mkpath(strParentPath.replace("/","\\"));
				if(bExist)
				{	
					QFile::copy(strPathSrc,strPathDst);//拷贝文件
				}
			}
		}
	}
	QApplication::restoreOverrideCursor();

}
void CFileLink::on_btnLink_clicked()
{
	QItemSelectionModel *selModel = treeViewSrc->selectionModel();
	if(selModel==NULL)
		return;
	QString strFolderSrc = cboFolderSrc->currentText();strFolderSrc.replace("\\","/");
	QString strFolderDst = cboFolderDst->currentText();strFolderDst.replace("\\","/");

	QModelIndexList modelList = selModel->selectedRows();
	for(int i=0; i<modelList.size(); i++)
	{
		QFileInfo fiSrc = m_dirModelSrc.fileInfo(modelList[i]);
		if(fiSrc.isDir())
		{
			QString strPathSrc = fiSrc.filePath();
			QString strPathDst = strPathSrc;
			strPathDst.replace(strFolderSrc,strFolderDst);
			QModelIndex idx = m_dirModelDst.index(strPathDst);
			if(idx.isValid())	
			{	// 目录已经存在
				continue;
			}
			else
			{
				QDir dirParent(fiSrc.filePath());
				dirParent.cdUp();
				QString strParentPath = dirParent.path();
				strParentPath.replace(strFolderSrc,strFolderDst);
				dirParent.setPath(strParentPath);
				bool bExist = dirParent.exists();
				if(!bExist)
					bExist = dirParent.mkpath(strParentPath.replace("/","\\"));
				if(bExist)
				{	// 建立软连接
					strPathSrc.replace("/","\\");
					strPathDst.replace("/","\\");
					QString strCmd;
					QString strProcess("mklink");
					strCmd = QString("%1 /D \"%2\" \"%3\"").arg(strProcess,strPathDst,strPathSrc);
//					WinExec(QString("cmd /c \"%1\"").arg(strCmd).toLocal8Bit().data(), SW_HIDE); 
//					::system(strCmd.toLocal8Bit().data());
 					bool bOK = :: CreateSymbolicLink(strPathDst.utf16(),strPathSrc.utf16(),SYMBOLIC_LINK_FLAG_DIRECTORY);
					idx = m_dirModelDst.index(strParentPath);
// 					if(idx.isValid())
// 						m_dirModelDst.refresh(idx);
				}
			}
		}
		else if(fiSrc.isFile())
		{
			QString strPathSrc = fiSrc.filePath();
			QString strPathDst = strPathSrc;
			strPathDst.replace(strFolderSrc,strFolderDst);
			QModelIndex idx = m_dirModelDst.index(strPathDst);
			if(idx.isValid())	
			{	// 文件已经存在
				continue;
			}
			else
			{
				QDir dirParent(fiSrc.path());
				QString strParentPath = dirParent.path();
				strParentPath.replace(strFolderSrc,strFolderDst);
				dirParent.setPath(strParentPath);
				bool bExist = dirParent.exists();
				if(!bExist)
					bExist = dirParent.mkpath(strParentPath.replace("/","\\"));
				if(bExist)
				{	// 建立软连接
					strPathSrc.replace("/","\\");
					strPathDst.replace("/","\\");
					QString strCmd;
					QString strProcess("mklink");
					strCmd = QString("%1 \"%2\" \"%3\"").arg(strProcess,strPathDst,strPathSrc);
					//					WinExec(QString("cmd /c \"%1\"").arg(strCmd).toLocal8Bit().data(), SW_HIDE); 
					//					::system(strCmd.toLocal8Bit().data());
					bool bOK = :: CreateSymbolicLink(strPathDst.utf16(),strPathSrc.utf16(),0);
					idx = m_dirModelDst.index(strParentPath);
					//					if(idx.isValid())
					//						m_dirModelDst.refresh(idx);
				}
			}
		}
	}

}

void CFileLink::slot_cboFilter_editTextChanged(const QString &strTxt)
{
	QTreeView *treeView = treeViewSrc;
	CDirModel *dirModel = &m_dirModelSrc;
	QStringList filters = strTxt.split(" ",QString::SkipEmptyParts);

	if(treeViewSrc->model()!=NULL)
		m_dirModelSrc.setNameFilters(filters);

	if(treeViewDst->model()!=NULL)
		m_dirModelDst.setNameFilters(filters);

}

/*
bool CFileLink::openShellContextMenuForObject(const std::wstring &path, int xPos, int yPos, void * parentWindow)
{
	assert (parentWindow);
	ITEMIDLIST * id = 0;
	std::wstring windowsPath = path;
	std::replace(windowsPath.begin(), windowsPath.end(), '/', '\\');
	HRESULT result = SHParseDisplayName(windowsPath.c_str(), 0, &id, 0, 0);
	if (!SUCCEEDED(result) || !id)
		return false;
	CItemIdListReleaser idReleaser (id);

	IShellFolder * ifolder = 0;

	LPCITEMIDLIST idChild = 0;
	result = SHBindToParent(id, IID_IShellFolder, (void**)&ifolder, &idChild);
	if (!SUCCEEDED(result) || !ifolder)
		return false;
	CComInterfaceReleaser ifolderReleaser (ifolder);

	IContextMenu * imenu = 0;
	result = ifolder->GetUIObjectOf((HWND)parentWindow, 1, (const ITEMIDLIST **)&idChild, IID_IContextMenu, 0, (void**)&imenu);
	if (!SUCCEEDED(result) || !ifolder)
		return false;
	CComInterfaceReleaser menuReleaser(imenu);

	HMENU hMenu = CreatePopupMenu();
	if (!hMenu)
		return false;
	if (SUCCEEDED(imenu->QueryContextMenu(hMenu, 0, 1, 0x7FFF, CMF_NORMAL)))
	{
		int iCmd = TrackPopupMenuEx(hMenu, TPM_RETURNCMD, xPos, yPos, (HWND)parentWindow, NULL);
		if (iCmd > 0)
		{
			CMINVOKECOMMANDINFOEX info = { 0 };
			info.cbSize = sizeof(info);
			info.fMask = CMIC_MASK_UNICODE;
			info.hwnd = (HWND)parentWindow;
			info.lpVerb  = MAKEINTRESOURCEA(iCmd - 1);
			info.lpVerbW = MAKEINTRESOURCEW(iCmd - 1);
			info.nShow = SW_SHOWNORMAL;
			imenu->InvokeCommand((LPCMINVOKECOMMANDINFO)&info);
		}
	}
	DestroyMenu(hMenu);

	return true;
}
*/